package com.xjt.query.action.interceptor;

import java.util.Collections;
import java.util.HashMap;
import java.util.Set;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.WildcardHelper;

/**
 * url过滤器
 */
public abstract class UrlPaternInterceptor extends AbstractInterceptor {

    private static final long serialVersionUID = 4442618963455361317L;

    protected Set<String>     excludeUrls      = Collections.emptySet();
    protected Set<String>     includeUrls      = Collections.emptySet();

    public void setExcludeUrls(String excludeUrls) {
        this.excludeUrls = TextParseUtil.commaDelimitedStringToSet(excludeUrls);
    }

    public Set<String> getExcludeUrlsSet() {
        return excludeUrls;
    }

    public void setIncludeUrls(String includeUrls) {
        this.includeUrls = TextParseUtil.commaDelimitedStringToSet(includeUrls);
    }

    public Set<String> getIncludeUrlsSet() {
        return includeUrls;
    }

    public String intercept(ActionInvocation invocation) throws Exception {
        if (isUrlMatch()) {
            return doIntercept(invocation);
        }
        return invocation.invoke();
    }

    /**
     * url是否匹配
     * 
     * @return
     */
    protected boolean isUrlMatch() {
        String path = ServletActionContext.getRequest().getServletPath();
        return match(includeUrls, excludeUrls, path);
    }

    /**
     * 匹配url是否包含在其中，在includeUrls中没有匹配上直接返回false，匹配成功再去匹配excludeUrls；如果在excludeUrls匹配上返回false，没有匹配上返回true
     * 
     * @param includeUrls
     * @param excludeUrls
     * @param url
     * @return
     */
    public static boolean match(Set<String> includeUrls, Set<String> excludeUrls, String url) {

        if (url == null || url.isEmpty()) {
            return false;
        }

        // 都没有配置
        if (includeUrls.size() == 0 && excludeUrls.size() == 0) {
            return false;
        }

        boolean needsPatternMatch = false;
        for (String includeUrl : includeUrls) {
            if (!"*".equals(includeUrl) && includeUrl.contains("*")) {
                needsPatternMatch = true;
            }
        }

        for (String excludeUrl : excludeUrls) {
            if (!"*".equals(excludeUrl) && excludeUrl.contains("*")) {
                needsPatternMatch = true;
            }
        }

        if (!needsPatternMatch && (includeUrls.contains("*") || includeUrls.size() == 0)) {
            if (excludeUrls != null && excludeUrls.contains(url) && !includeUrls.contains(url)) {
                return false;
            }
        }

        // 通配符比较
        WildcardHelper wildcard = new WildcardHelper();

        String urlCopy = new String(url);

        boolean isIncluded = false;

        if (includeUrls.contains("*")) {
            isIncluded = true;
        } else {
            for (String pattern : includeUrls) {
                if (pattern.contains("*")) {
                    int[] compiledPattern = wildcard.compilePattern(pattern);
                    HashMap<String, String> matchedPatterns = new HashMap<String, String>();
                    boolean matches = wildcard.match(matchedPatterns, urlCopy, compiledPattern);
                    if (matches) {
                        isIncluded = true; // 通配成功
                    }
                } else {
                    if (pattern.equals(urlCopy)) {
                        isIncluded = true; // 全词匹配成功
                    }
                }
            }
        }

        if (!isIncluded) {// includeUrls中没有匹配，直接返回false
            return false;
        }

        if (excludeUrls.contains("*")) {
            return false;
        }

        for (String pattern : excludeUrls) {
            if (pattern.contains("*")) {
                int[] compiledPattern = wildcard.compilePattern(pattern);
                HashMap<String, String> matchedPatterns = new HashMap<String, String>();
                boolean matches = wildcard.match(matchedPatterns, urlCopy, compiledPattern);
                if (matches) {
                    return false;// 通配成功
                }
            } else {
                if (pattern.equals(urlCopy)) {
                    return false;// 全词匹配成功
                }
            }
        }

        return isIncluded;

    }

    /**
     * 子类需要覆盖此方法
     * 
     * @param invocation
     * @return
     * @throws Exception
     */
    protected abstract String doIntercept(ActionInvocation invocation) throws Exception;
}
